package org.musicPlayerServer.music;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Map;

import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.AudioDevice;
import javazoom.jl.player.FactoryRegistry;
import javazoom.jl.player.advanced.PlaybackListener;
import javazoom.jlgui.basicplayer.BasicController;
import javazoom.jlgui.basicplayer.BasicPlayer;
import javazoom.jlgui.basicplayer.BasicPlayerEvent;
import javazoom.jlgui.basicplayer.BasicPlayerException;
import javazoom.jlgui.basicplayer.BasicPlayerListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.PropertyConfigurator;
import org.musicPlayerServer.business.ContentManager;
import org.musicPlayerServer.business.object.Music;

public class MusicPlayer {

    BasicPlayer currentPlayer;

    Thread currentThread;

    Log log = LogFactory.getLog(getClass());


    Music currentMusic = null;

    static MusicPlayer soleInstance = new MusicPlayer();

    MusicPlayer me = this;

    PlaybackListener listener;

    Boolean play = false;

    ContentManager cm;

    public void setContentManager(ContentManager cm) {
	this.cm = cm;
    }

    private MusicPlayer() {    }

    public static MusicPlayer getInstance() {
	return soleInstance;
    }


    BasicPlayerListener bpl = new BasicPlayerListener(){

	/**
	 * Open callback, stream is ready to play.
	 *
	 * properties map includes audio format dependant features such as
	 * bitrate, duration, frequency, channels, number of frames, vbr flag, ...
	 *
	 * @param stream could be File, URL or InputStream
	 * @param properties audio stream properties.
	 */
	public void opened(Object stream, Map properties){
	    // Pay attention to properties. It's useful to get duration,
	    // bitrate, channels, even tag such as ID3v2.
	    //log.info("opened : "+properties.toString());
	}
	/** * Progress callback while playing.
	 *
	 * This method is called severals time per seconds while playing.
	 * properties map includes audio format features such as
	 * instant bitrate, microseconds position, current frame number, ...
	 *
	 * @param bytesread from encoded stream.
	 * @param microseconds elapsed (<b>reseted after a seek !</b>).
	 * @param pcmdata PCM samples.
	 * @param properties audio stream parameters.
	 */
	public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties){
	    // Pay attention to properties. It depends on underlying JavaSound SPI
	    // MP3SPI provides mp3.equalizer.
	    //display("progress : "+properties.toString());
	}
	/**
	 * Notification callback for basicplayer events such as opened, eom ...
	 *
	 * @param event
	 */
	public void stateUpdated(BasicPlayerEvent event){
	    // Notification of BasicPlayer states (opened, playing, end of media, ...)
	    log.info("stateUpdated : "+event.toString());
	    if(event.getCode()==BasicPlayerEvent.EOM){
		log.info("End of Media");
		playNext();


	    }
	}
	/**
	 * A handle to the BasicPlayer, plugins may control the player through
	 * the controller (play, stop, ...)
	 * @param controller : a handle to the player
	 */ 
	public void setController(BasicController controller){
	}




    };


    public void playNext(){
	if(play){
	    log.info("continuous play is on");
	    log.info("getting next ");
	    Music next = cm.getNextMusic(currentMusic);
	    if(next==null){
		log.info("next is null stoping continuous play");
		play = false;
	    }else{
		log.info("set current = next ");
		currentMusic = next;
		try {
		    log.info("play ");
		    play();
		} catch (Exception e) {
		    log.error(e);
		}
	    }

	}
    }


 

    /* public void playWithRetry()  throws Exception  {

	Integer retry = 5;
	while(playOneFile()==0&&retry>0){
	    log.error("playing too fast retry "+retry);
	    Thread.sleep(1000);		    
	    retry--;
	}
    }*/

    public void play()throws Exception  {
	play = true;
	currentPlayer = new BasicPlayer();
	currentPlayer.open(new File(currentMusic.getFilePath()));
	currentPlayer.addBasicPlayerListener(bpl);
	log.info("Playing : "+currentMusic);
	currentPlayer.play();
	
    }

  

    public static void main(String[] args) {
	PropertyConfigurator.configure("log4j.properties");
	try {
	    MusicPlayer.getInstance().select(new Music ("/home/flo/Musique/allByStyle/quantic & nickodemus - mi swing es tropical.mp3"));
	    MusicPlayer.getInstance().play();
	    //MusicPlayer.getInstance().play("/home/flo/Musique/allByStyle/Rihanna-SOS.mp3");
	} catch (Exception e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}
    }

    public void select(Music music) {
	//fileToPlay = music.getFilePath();
	currentMusic = music;
    }

    public void pause() throws BasicPlayerException {
	if (currentPlayer!=null){
	    currentPlayer.pause();
	}
    }

    public void resume() throws BasicPlayerException {
	if (currentPlayer!=null){
	    currentPlayer.resume();
	}
    }

    /*public Boolean isMusicToStop(){
	return currentPlayer!=null;
    }*/

    public void stop() throws BasicPlayerException{
	play = false;
	if (currentPlayer!=null){
	    currentPlayer.stop();
	}
    }
}
